﻿using System;
using System.Collections;
using System.Collections.Generic;
using GameFramework.timer;
using UnityEngine;

namespace GameFramework.buff
{
    //https://zhuanlan.zhihu.com/p/150812545
    public class BuffManager:MonoBehaviour
    {
        //管理所有拥有的buff
        private List<BaseBuff> _buffs = new List<BaseBuff>();
        
        //buff流程
        //1.Buff创建前检查当前Buff是否可创建。一般主要是检测目标身上是否存在免疫该Buff的相关Buff，如果被免疫则不会创建该Buff。
        //2.Buff在实例化之后，生效之前（还未加入到Buff容器中）时会抛出一个OnBuffBeforeAdd事件。
        //如果存在某种Buff的效果是：受到负面效果时，驱散当前所有负面效果，并给自己加一个护盾。那么这个时候就需要监听OnBuffBeforeAdd事件了，
        //此时会给自己加护盾，并且把所有负面Buff驱散。这意味着一个Buff可能还未生效之前即销毁了（小心Buff的生命周期）
        //3.当Buff生效时（加入到Buff容器后），我们提供给策划一个抽象接口OnBuffAfterAdd，由策划配置具体效果。
        //4.当Buff添加时存在相同类型且Releaser相等的时候，Buff执行刷新流程（更新Buff层数，等级，持续时间等数据）。
        //我们提供给策划一个抽象接口OnBuffRefresh，由策划配置具体效果。
        //5.当Buff销毁前（还未从Buff容器中移除），我们提供给策划一个抽象接口OnBuffBeforeDestroy，由策划配置具体效果
        //6.当Buff销毁后（已从Buff容器中移除），我们提供给策划一个抽象接口OnBuffAfterDestroy，由策划配置具体效果。
        //7.Buff还可以创建定时器，以触发间隔持续效果。通过策划配置时调用StartIntervalTrigger操作，提供OnIntervalTrigger抽象接口供策划配置具体效果。
        //第8不需要运动系统进行配合，ApplyMotion让运动系统的update里运行buff的运动片段（运动分为覆盖和叠加），
        //覆盖：进出运动停止（不响应用户输入和基本运动），待buff的运动片段播放完后才响应用户输入
        //叠加：基础运动和buff运动片段需要叠加计算运动速度和方向等，计算后改变角色的移动状态
        //在buff的运动片段期间，需要每帧或设置的间隔检测，来回调buff的OnMotionUpdate，比如添加一个buff后直线坠落到地面，然后造成伤害，则需要每帧检测释放到地面了
        //8.Buff还可以通过请求改变运动来触发相关效果。通过策划配置时调用ApplyMotion操作，提供OnMotionUpdate和OnMotionInterrupt接口供策划配置具体效果。
        
        //Buff可以通过修改状态去影响角色行为逻辑。以下列举一些最常见的状态：

        //Stun（眩晕状态——目标不再响应任何操控）
        //Root（缠绕，又称定身——目标不响应移动请求，但是可以执行某些操作，如施放某些技能）
        //Silence （沉默——目标禁止施放技能）
        //Invincible (无敌——几乎不受到所有的伤害和效果影响）
        //Invisible (隐身——不可被其他人看见）
        
        //非常多的游戏效果实际上都是这几种状态+运动+动画的组合。

        public List<BaseBuff> getAllBuffs()
        {
            return _buffs;
        }

        public void addBuff(BaseBuff buff)
        {
            //检测buff释放可创建
            if (!canAdd(buff))
            {
                return;
            }
            //buff加入容器前
            if (!buff.OnBuffBeforeAdd(_buffs))
            {
                return;
                //销毁buff
            }
            
            // BaseBuff newBuff = buff.OnBuffRefresh(_buffs);
            //刷新buff由buff 管理器来做
            BaseBuff newBuff = refreshBuff(buff);

            if (buff == newBuff)//新增buff
            {
                _buffs.Add(buff);
                //加入后
                buff.OnBuffAfterAdd(_buffs);
                BuffConfig buffConfig = buff.buffConfig;
                //看是否要定时处理
                if (buffConfig.duration>0)
                {
                    // buff.coroutine = StartCoroutine(buffInterval(buff));
                    //叠加层数，重置时间，
                    createBuffTimer(buff);
                }
                else//没有持续时间则立即执行一次
                {
                    buff.OnIntervalTrigger(_buffs);
                }
            }
            else//刷新buff
            {
                buff.OnIntervalTrigger(_buffs);
                buff.times++;
            }


        }
        //buff刷新
        //1.同源
        //-----1.层数增加，不重置时间
        //-----2.层数增加，重置时间
        //-----3.重置时间
        //-----4.累加时间
        //2.不同源
        //-----1.不合并，单独存在
        //-----2.合并，源都设置为空(一般为某些boss)
        private BaseBuff refreshBuff(BaseBuff buff)
        {
            var buffConfig = buff.buffConfig;
            int mergeType = buffConfig.mergeType;//非同源buff的合并类型
            List<BaseBuff> oldBuffs = _buffs.FindAll(old =>
            {
                return buff.id == old.id ;
            });
            //同源的buff
            BaseBuff sameSource = oldBuffs.Find(b => b.releaser.Equals(buff.releaser));
            //非同源buff
            BaseBuff noSameSource = oldBuffs.Find(b => !b.releaser.Equals(buff.releaser));
            if (mergeType == 1)
            {
                if (noSameSource == null)
                {
                    return buff;
                }
                refreshOldBuff(noSameSource, buffConfig);
                //TODO 不同目标的buff合并
                return noSameSource;
            }

            if (mergeType == 2)//不同目标单独存在，则看下同源buff是否有，有就刷新老buff
            {
                if (sameSource == null)
                {
                    return buff;
                }
                refreshOldBuff(sameSource, buffConfig);
                
                return sameSource;
            }
            if (mergeType == 3)//有了同类buff后，后续的buff不处理
            {
                if (sameSource == null)
                {
                    return buff;
                }
                
                return noSameSource;
            }
            Debug.LogError("未处理的buff合并类型:"+buffConfig.mergeType+"  buffId:"+buffConfig.id);
            return buff;
        }

        //同源buff的叠加类型
        //1.层数叠加，不重置时间
        //2.层数叠加，重置时间
        //3.重置时间
        //4.累加时间
        //5.不处理(有了相同buff，其他buff来了不生效,比如相同类型的回血buff，回血不叠加)
        //TODO 如果类型少且固定，直接几个if就行，如果类型太多，就写成策略模式
        private void refreshOldBuff(BaseBuff old, BuffConfig buffConfig)
        {
            if (old == null || buffConfig==null)
            {
                return;
            }

            Timer timer = TimerManager.Instance.getTimer(old.timerId);
            if (buffConfig.overlapType == 1)//增加层数，不重置时间
            {
                old.layer++;
                return;
            }
            if (buffConfig.overlapType == 2)//增加层数，重置时间
            {
                old.layer++;
                //Timer重置时间
                if (timer != null)
                {
                    //移除老timer，创建新timer
                   TimerManager.Instance.removeTimer(old.timerId);
                   createBuffTimer(old);
                }
            }
            if (buffConfig.overlapType == 3)//重置时间
            {
                //Timer重置时间
                if (timer != null)
                {
                    //移除老timer，创建新timer
                    TimerManager.Instance.removeTimer(old.timerId);
                    createBuffTimer(old);
                }
            }
            if (buffConfig.overlapType == 4)//时间累加
            {
                //要重新计算累加后的delay,和duration,次数
                //duration
                old.duration =old.duration-old.gone+ buffConfig.duration;
                //delay,计算的值大于0才表示有interval的执行情况
                float newDelay= timer.delay+ timer.interval * (timer.hadActionTimes + 1) - timer.passedTime;
                newDelay = newDelay >= 0 ? newDelay : 0;
                //剩余要生效的次数
                int remainTime = old.times-timer.hadActionTimes;
                
                //Timer重置时间
                if (timer != null)
                {
                    //移除老timer，创建新timer
                    TimerManager.Instance.removeTimer(old.timerId);
                    TimerManager.Instance.schedule(
                        t => buffInterval(t, old),
                        t => destroyBuff(old),
                        newDelay, remainTime, buffConfig.interval, old.duration, buffConfig.noTimesToEnd
                    );
                }
            }
            if (buffConfig.overlapType == 4)//不处理
            {
                //do nothing
            }
        }

        private void createBuffTimer(BaseBuff buff)
        {
            if (buff == null)
            {
                return;
            }

            BuffConfig buffConfig = buff.buffConfig;
            buff.duration = buffConfig.duration;
            buff.timerId = TimerManager.Instance.schedule(
                timer => buffInterval(timer,buff),
                (timer)=>destroyBuff(buff),
                buffConfig.delay,buffConfig.effectTimes,buffConfig.interval,buffConfig.duration,buffConfig.noTimesToEnd
            );
            Debug.Log("添加定时器成功！");
        }

        public void buffInterval(Timer timer,BaseBuff buff)
        {
            buff.gone = timer.passedTime;
            buff.OnIntervalTrigger(_buffs); 
            buff.times++;
        }

        
        //检测buff是否可释放
        private bool canAdd(BaseBuff buff)
        {
            //TODO 看buff优先级，互斥buff
            return true;
        }


        public void destroyBuff(BaseBuff buff)
        {

            if (!_buffs.Contains(buff))
            {
                return;
            }

            try
            {
                buff.OnBuffBeforeDestroy(_buffs);
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }

            //停止关联的timer
            if (buff.timerId != 0)
            {
                TimerManager.Instance.removeTimer(buff.timerId);
            }
            Debug.Log("buff被移除！");
            _buffs.Remove(buff);
            try
            {
                buff.OnBuffAfterDestroy(_buffs);
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
        }
    }
}